package org.atf.services;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.atf.mgr.ATFNotifications;
import org.atf.mgr.AppManager;
import org.atf.mgr.ProfileManager;
import org.atf.mgr.WASAppManagerImpl;
import org.atf.mgr.WASNotificationImpl;
import org.atf.mgr.WASProfileManagerImpl;
import org.atf.model.dao.AtfSchedulerDAO;
import org.atf.model.dao.PreferenceDAO;
import org.atf.model.dao.ProfileDAO;
import org.atf.model.dao.ServerDAO;
import org.atf.model.entity.Preference;
import org.atf.model.entity.Profile;
import org.atf.model.entity.Server;
import org.atf.model.entity.User;
import org.atf.utils.ATFUtils;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
public class TaskManager {
	ProfileDAO profileDAO = new ProfileDAO();
	ServerDAO serverDAO= new ServerDAO();
	PreferenceDAO preferenceDAO= new PreferenceDAO();
	private static TaskManager taskManager = null;
	private static Logger logger = Logger.getLogger(TaskManager.class);
	private static Map<Integer, ProfileManager> profileMgrStore= new ConcurrentHashMap<Integer, ProfileManager>();
	private static Map<Integer, AppManager> appMgrStore= new HashMap<Integer, AppManager>();
	private static Map<Integer,ATFNotifications> atfNotificationStore= new ConcurrentHashMap<Integer, ATFNotifications>();
	private String APP_USERNAME_HEADER=ATFUtils.APP_USERNAME_HEADER;
	protected TaskManager(){
		APP_USERNAME_HEADER=ATFUtils.getAppUserHeader();
	}
	
	public static TaskManager getInstance(){
		if(taskManager == null){
			logger.debug("Creating a new TaskManager...");
			taskManager = new TaskManager();
		}
		return taskManager;
	}
	
	public String getUsername(){
		logger.debug("Getting ther User from Context");
		WebContext ctx = WebContextFactory.get();
		HttpSession session=ctx.getSession();
		User user =(User) session.getAttribute("ATFUser");
		if( user != null){
			return user.getUsername();
		}else{
			return "";
		}
	}
	public String deployApplication(HashMap<String, String> options){
		
		if(!options.containsKey("serverId")){
			return "Error: Request does't contain server ID:";
		}
		Integer serverId= Integer.valueOf(options.get("serverId"));
		String result= "";
		if(!appMgrStore.containsKey(serverId)){
			try {
				Integer profileId =profileDAO.getProfileIdByServerId(serverId);
				initializeAppManager(profileId, serverId);	
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result= "ERROR: "+e.getMessage();
				logger.error(e.getMessage());
			}
		}
		if(appMgrStore.containsKey(serverId)){
			if(!appMgrStore.get(serverId).isRunning()){
				appMgrStore.get(serverId).setUsername(getUsername());
				appMgrStore.get(serverId).deploy(options);
				result="OK";
			}else{
				result="WARN: Task already running for this Server";
				logger.warn("Task is already running "+serverId);
			}
		}
		
		return result;
	}
	public String restartServer(Integer serverId ){
		logger.debug("restart Server request... ServerId: "+serverId);
		String result= "";
		if(!appMgrStore.containsKey(serverId)){
			try {
				Integer profileId =profileDAO.getProfileIdByServerId(serverId);
				initializeAppManager(profileId, serverId);	
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result= "ERROR: "+e.getMessage();
				logger.error(e.getMessage());
			}
		}
		if(appMgrStore.containsKey(serverId)){
			if(!appMgrStore.get(serverId).isRunning()){
				appMgrStore.get(serverId).setUsername(getUsername());
				appMgrStore.get(serverId).restartServer();
				result="OK";
			}else{
				result="WARN: Task already running for this Server";
				logger.warn("Task is already running "+serverId);
			}
		}
		
		return result;
		
	}
	
	
	public String stopServer(Integer serverId){
		String result= "";
		logger.debug("Stop Server :"+serverId);
		if(!appMgrStore.containsKey(serverId)){
			logger.debug("Server is not in the appManager Store.. Will to initilize and Add");
			try {
				
				Integer profileId =profileDAO.getProfileIdByServerId(serverId);
				initializeAppManager(profileId, serverId);	
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result= "ERROR: "+e.getMessage();
				logger.error(e.getMessage());
			}
		}
		if(appMgrStore.containsKey(serverId)){
			logger.debug("Server AppManager Found....");
			if(!appMgrStore.get(serverId).isRunning()){
				logger.debug("No Task is  running . Will initiate new task");
				appMgrStore.get(serverId).setUsername(getUsername());
				logger.debug("Stop Server...");
				appMgrStore.get(serverId).stopServer();
				result="OK";
				logger.debug("OK Scheduled...");
			}else{
				result="WARN: Task already running for this Server";
				logger.warn("Task is already running "+serverId);
			}
		}
		
		return result;
	}
	public String updateServersList(Integer profileId){
		String result= "";	
		logger.debug("User Server List Server :"+profileId);
		if(!profileMgrStore.containsKey(profileId)){
			System.out.println("Profile Manager not Found for Profileid: "+profileId);
			System.out.println("Creating the new ProfileManager");
			try {
				initializeProfileManager(profileId);
				
			}catch ( Exception e){
				System.err.println(e.getMessage());
				e.printStackTrace();
				result="ERROR:"+e.getMessage();
			}
		}
		if(profileMgrStore.containsKey(profileId)){
			List<Server> serverList=profileMgrStore.get(profileId).getServersList();
			System.out.println(serverList);
			if(serverList.size() > 0){
				profileDAO.addOrUpdateServers(profileId,serverList);
				result="SUCCESS: Update Of Servers Complete";
			}
		}else{
			result="ERROR: Profile  is unvailable now";
		}
		return result;
	}
	
	public String startServer(Integer serverId){
		String result= "";
		logger.debug("Start Server :"+serverId);
		if(!appMgrStore.containsKey(serverId)){
			logger.debug("Server is not in the appManager Store.. Will to initilize and Add");
			try {
				Integer profileId =profileDAO.getProfileIdByServerId(serverId);
				initializeAppManager(profileId, serverId);	
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result= "ERROR: "+e.getMessage();
				logger.error(e.getMessage());
			}
		}
		if(appMgrStore.containsKey(serverId)){
			logger.debug("Server AppManager Found....");
			if(!appMgrStore.get(serverId).isRunning()){
				logger.debug("No Task is  running . Will initiate new task");
				appMgrStore.get(serverId).setUsername(getUsername());
				logger.debug("Start Server...");
				appMgrStore.get(serverId).startServer();
				result="OK";
				logger.debug("OK Scheduled...");
			}else{
				result="WARN: Task already running for this Server";
				logger.warn("Task is already running "+serverId);
			}
		}
		
		return result;
	}
	public String testConnection(Integer profileId){
		String result= "";
		if(profileMgrStore.containsKey(profileId)){
			if( profileMgrStore.get(profileId).testConnection()){
				result= "SUCCESS: Test Connection successfull";
			}else{
				result= "WARN: Test Connection Failed";
			}
			
		}else{
			logger.debug("Profile Manager not Found for Profileid: "+profileId);
			logger.debug("Creating the new ProfileManager");
			try {
				initializeProfileManager(profileId);
				if(profileMgrStore.containsKey(profileId)){
					if( profileMgrStore.get(profileId).testConnection()){
						result= "SUCCESS: Test Connection successfull";
					}else{
						result= "WARN: Test Connection Failed";
					}
				}else{
					result="ERROR: Profile  is unvailable now";
				}
			}catch ( Exception e){
				logger.error(e.getMessage());
				e.printStackTrace();
				result="ERROR:"+e.getMessage();
			}
		}
		return result;
	}
	public List<HashMap<String, String>> getProfileRuntimeDetails(){
		List<HashMap<String, String>> result= new ArrayList<HashMap<String,String>>();
		Iterator<Map.Entry<Integer, ProfileManager>> entries = profileMgrStore.entrySet().iterator();
		while (entries.hasNext()) {
		  Map.Entry<Integer, ProfileManager> entry = entries.next();
		  Integer key = entry.getKey();
		  ProfileManager profileManager = entry.getValue();
		  HashMap<String,String> temp= new HashMap<String, String>();
		  temp.put("profileName", profileManager.getProfileDetails().getProfileName());
		  temp.put("id", String.valueOf(key));
		  if(profileManager.getConnectedTime() != null){
			  temp.put("startTime", profileManager.getConnectedTime().getTime().toString());
		  }else{
			  temp.put("startTime", "");
		  }
		  temp.put("status",String.valueOf(profileManager.isConnected()));
		  result.add(temp);
		}
		return result;
		
	}
	public String stopProfileRuntimeDetails(Integer profileId){
		String result= "";
		logger.info("Stoping/Clear the Profile Manager");
		if(profileMgrStore.containsKey(profileId)){
			logger.info("Profile Manager Found for Id: "+profileId);
			logger.info("Destroying the Profile");
			profileMgrStore.get(profileId).destroyProfile();
			logger.info("Removing the Profile from the Profile Manager Store");
			logger.info("Before Profile Manager Store Size: "+profileMgrStore.size());
			profileMgrStore.remove(profileId);
			logger.info("After Profile Manager Store Size: "+profileMgrStore.size());
			logger.info("Removing the Notification Mgr from Store");
			if(atfNotificationStore.containsKey(profileId)){
				logger.info("Found one Removing it...");
				logger.info("Before Notification Manager Store Size: "+atfNotificationStore.size());
				atfNotificationStore.remove(profileId);
				logger.info("After Notification Manager Store Size: "+atfNotificationStore.size());
			}
			result= "OK";
		}else{
			result= "ERROR: Profile Not Found";
		}
		return result;
	}
	public String serverStatus(Integer serverId){
		String result= "";
		logger.debug("Getting the Server Status: ServerId: "+serverId);
		if(!appMgrStore.containsKey(serverId)){
			logger.debug("Server is not in the appManager Store.. Will to initilize and Add");
			try {
				Integer profileId =profileDAO.getProfileIdByServerId(serverId);
				initializeAppManager(profileId, serverId);	
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				result= "ERROR: "+e.getMessage();
				logger.error(e.getMessage());
			}
		}
		if(appMgrStore.containsKey(serverId)){
			logger.debug("Server AppManager Found....");
			if(!appMgrStore.get(serverId).isRunning()){
				logger.debug("No Task is  running . Will initiate new task");
				appMgrStore.get(serverId).setUsername(getUsername());
				logger.debug("Get Status...");
				appMgrStore.get(serverId).serverStatus();
				result="OK";
			}else{
				result="WARN: Task already running for this Server";
				logger.warn("Task is already running "+serverId);
			}
			
			
		}else{
			result="ERROR: Unable to Schedule";
			logger.error("appMgrStore Does't content the Server cache"+serverId);
		}
		
		return result;
	}

	private void initializeAppManager(Integer profileId, Integer serverId) throws Exception{
		logger.info("Initializing the App  Manager");
		logger.info("Checking the Profile Manager:");
		if(!profileMgrStore.containsKey(profileId)){
			logger.info("Profile Manager does't exists... Creating new and storing");
			initializeProfileManager(profileId);
			
		}
		if(! profileMgrStore.containsKey(profileId)){
			logger.error("Profile Manager is not Found");
			return;
		}
		if(profileMgrStore.get(profileId).getProfileDetails().getProfileType().equalsIgnoreCase("WebSphere")){
			
			logger.info("WebSphere Profile Found.. Creating the App Mamanger");
			logger.info("WebSphere Profile Name: "+profileMgrStore.get(profileId).getProfileDetails().getProfileName());
			AppManager appManager = new WASAppManagerImpl();
			logger.info("AppManager init");
			logger.debug("Add Profile Manager to App Manager");
			appManager.setProfileManager(profileMgrStore.get(profileId));
			logger.debug("Adding Server Detail to AppManager");
			appManager.setServer(serverDAO.getServer(serverId));
			logger.info("App Manager Server Name is: "+appManager.getServer().getServername());
			logger.info("Addding The appManager to the cache");
			appMgrStore.put(serverId, appManager);
			logger.info("Current App manager Cache Size is "+appMgrStore.size());
			
		}else{
			logger.info("Unknown App Manager Type: "+profileId);
		}
		
		
	}
	private void initializeProfileManager(Integer profileId) throws Exception {
		// TODO Auto-generated method stub
		logger.info("Initializing the Profile Manager");
		logger.debug("Getting Profile from DB : profileId="+profileId);
		Profile profile = profileDAO.getProfile(profileId);
		if(profile == null){
			logger.error("Profile Does't Exists... DB return Null");
			return ;
		}
		String profileType= profile.getProfileType();
		logger.debug("Profile Type: "+profileType);
		if(profileType.equalsIgnoreCase("WebSphere")){
			
			logger.info("Init ProfileManger");
			ProfileManager profileManager= new WASProfileManagerImpl();
			logger.info("Setting Profile to ProfileManger");
			profileManager.setProfileDetails(profile);
			logger.info("Initialzing the Notifications Manager");
			ATFNotifications notification= new WASNotificationImpl();
			logger.info("Adding the Notifications Manager to Profile");
			profileManager.setNotification(notification);
			logger.debug("Calling the Profile Manager Initialize");
			profileManager.initialize();
			logger.info("Caching the Profile Manager");
			profileMgrStore.put(profileId, profileManager);
			logger.info("Profile Manager Store Size is : "+profileMgrStore.size());
			logger.info("Caching the Notifications Manager");
			atfNotificationStore.put(profileId, notification);
			logger.info("Notifications Manager Store Size is : "+profileMgrStore.size());
			
		}else{
			logger.info("Unknown Profile Type: "+profile.getProfileType());
		}
		
	}

	public List<TaskStatus> getAllAppTaskStatus() {
		// TODO Auto-generated method stub
		 List<TaskStatus> result  = new ArrayList<TaskStatus>();
		 logger.trace("Get App Task Status initited");
		 logger.trace("App Manager Store Size: "+appMgrStore.size());
		 Iterator iterator = appMgrStore.entrySet().iterator();
		 while(iterator.hasNext()){
			 Map.Entry<Integer, AppManager> entry = (Entry<Integer, AppManager>) iterator.next();
			 
			 TaskStatus ts= entry.getValue().getTaskStatus();
			 logger.trace("TaskStatus: "+ts.toString());
			 result.add(ts);
			 if(!entry.getValue().isRunning()){
				 logger.trace("App Manager is not running any Task.. Will Remove from the Store");
				 logger.trace("Issue Shutdown on App Manager");
				 entry.getValue().shutdown();
				 logger.trace("App Manager will be removed");
				 iterator.remove();
			 }

		 }
		 logger.trace("App Manager Store Size: "+appMgrStore.size());
		 return result;
	}
	

	public List<TaskStatus> getAllProfileTaskStatus() {
		// TODO Auto-generated method stub
		List<TaskStatus> result  = new ArrayList<TaskStatus>();
		return result;
	}

	public List<TaskStatus> getAllNotifications() {
		// TODO Auto-generated method stub
		List<TaskStatus> result  = new ArrayList<TaskStatus>();
		Iterator iterator = atfNotificationStore.entrySet().iterator();
		logger.trace("Get Notifications initited");
		logger.trace("Notification  Store Size: "+atfNotificationStore.size());
		while(iterator.hasNext()){
			 Map.Entry<Integer, ATFNotifications> entry = (Entry<Integer, ATFNotifications>) iterator.next();
			 List<TaskStatus> tsList= entry.getValue().getNotifications();
			 if(tsList.size() > 0){
				result.addAll(tsList);
			 }
			 entry.getValue().clearNotifications();
			
		 }
		logger.trace("Notification  Store Size: "+atfNotificationStore.size());
		return result;
	}
	
	
}


